window.okay = {}
okay.preload_img = function(list) {
    return new Promise((resolve, reject) => {
        let len = list.length
        let imgs = []
        list.forEach((item, i) => {
            let img = new Image()
            img.src = item
            if(img.complete) {
                imgs[i] = img
                len--
                if(len == 0) {
                    resolve(imgs)
                }
            }else {
                img.onload = ((j) => {
                    return function() {
                        imgs[j] = img
                        len--
                        if(len == 0) {
                            resolve(imgs)
                        }
                    }
                })(i)
                img.onerror = function (e) {
                    len--
                    console.log('fail to load ' + item)
                    reject(e)
                }
            }
        })
    })
}
okay.Canvas = class {
    constructor(config) {
        if(config.ele == undefined) {
            throw 'Not found config of ele'
        }
        this.canAction = config.canAction | false
        let container = document.getElementById(config.ele)
        if(container == undefined) {
            throw 'Not found Element'
        }
        let canvas = document.createElement('canvas')
        let width = parseInt(container.style.width.replace('px', ''))
        let height = parseInt(container.style.height.replace('px', ''))
        canvas.width = width
        canvas.height = height
        container.appendChild(canvas)
        this.selectNode = null
        this.painter = canvas.getContext('2d')
        this.ele = canvas
        this.width = width
        this.height = height
        this.childs = new Array()
        this.eventManager = new okay.EventManager(this)
        this.ele.setAttribute('tabindex', '0')
        this.ele.style.outline = 'none';
        this.ele.onclick = (e) => {
            this.ele.focus()
        }
        this.debug = config.debug?config.debug:false
        if(config.debug) {
            this.debug_text = new okay.Text("X:0,Y:0")
            this.debug_text.font = "15px Arial"
            this.debug_text.color = new okay.Color(0,0,0,255)
            this.debug_text.setPosition(this.width - this.debug_text.text.length/2 * 15, 15)
            this.ele.addEventListener("mousemove", (e) => {
                this.debug_text.text = "X:" + (e.pageX - this.ele.offsetLeft) + ",Y:" + (this.height - e.pageY + this.ele.offsetTop)
                this.debug_text.setPosition(this.width - this.debug_text.text.length/2 * 15, 15)
            })
            this.addChild(this.debug_text)
            this.debug_layer = new okay.DebugLayer(this)
            this.ele.style.cursor = "crosshair"
        }
        this.ele.addEventListener("keypress",(e) => {
            console.log(e.code)
        })
    }
    addChild(child) {
        if(child instanceof okay.Node) {
            if(this.childs.indexOf(child) == -1) {
                child.canvas = this
                this.childs.push(child)
            }else {
                this.childs.splice(this.childs.indexOf(child), 1)
                child.canvas  = this
                this.childs.push(child)
            }
        }else {
            throw 'Error Argument'
        }
    }
    removeChild(child) {
        if(this.childs.indexOf(child) != -1) {
            this.childs.splice(this.childs.indexOf(child), 1)
        }
    }
    paint() {
        this.painter.clearRect(0, 0, this.width, this.height)
        for(let i = 0;i < this.childs.length;i++) {
            this.childs[i].paint()
        }
        if(this.debug) {
            this.debug_layer.paint()
        }
        if(this.canAction) {
            setTimeout(() => {
                this.paint()
            }, Math.round(1000 / 60))
        }
    }
}
okay.Point = class {
    constructor(_x, _y) {
        this.x = _x
        this.y = _y
    }
    add(point, _y = 0) {
        if(point instanceof okay.Point) {
            this.x += point.x
            this.y += point.y
        }else if(/^[0-9]*\.?[0-9]*/.test(point)) {
            this.x += point
            this.y += _y
        }else {
            throw 'Type Error'
        }
    }
    sub(pointer, _y = 0) {
        if(point instanceof okay.Point) {
            this.x -= point.x
            this.y -= point.y
        }else if(/^[0-9]*\.?[0-9]*/.test(point)) {
            this.x -= point
            this.y -= _y
        }else {
            throw 'Type Error'
        }
    }
}
okay.Size = class {
    constructor(_width, _height) {
        this.width = _width
        this.height = _height
    }
}

okay.Scheduler = class {
    constructor(_scheduler, _callback) {
        this.scheduler = _scheduler
        this.callback = _callback
    }
}
okay.Action = class {
    constructor(_duration) {
        this.running = true
        this.duration = _duration * 60
        this.currentFrame = _duration * 60
    }
    run (node) {
        this.update(node, this.currentFrame)
        this.currentFrame--
        if(this.currentFrame > 0 && this.running) {
            setTimeout(()=>{this.run(node)}, Math.round(1000/60))
        }
    }
    stop() {
        this.running = false
    }
    update(node,frame) {

    }
    restart(node) {
        this.running = true
        this.run(node)
    }
    reset() {
    }
}
okay.ActionMove = class extends okay.Action {
    constructor(_duration, _destination) {
        super(_duration)
        this.destination = _destination
    }
    run(_sprite) {
        let origin = _sprite.getPosition()
        if (this.destination.x != origin.x) {
            let k = (this.destination.y - origin.y) / (this.destination.x - origin.x)
            let deta = (this.destination.x - origin.x) / this.currentFrame
            _sprite.setPosition(origin.x + deta, origin.y + deta * k)
        } else {
            this.deta = (this.destination.y - origin.y) / this.currentFrame
            _sprite.setPosition(origin.x, origin.y + deta)
        }
        this.currentFrame--
        if(this.currentFrame > 0 && this.running) {
            setTimeout(()=>{this.run(_sprite)}, Math.round(1000/60))
        }
    }
    directTo(_destination, _duration) {
        this.destination = _destination
        this.duration = _duration
    }
    reset() {
        this.running = true
        this.currentFrame = this.duration
    }
}
okay.ActionScale = class extends okay.Action {
    constructor(_duration, _scaleX, _scaleY) {
        super(_duration)
        this.scaleX = _scaleX
        this.scaleY = _scaleY
        this.detaX = (this.scaleX - 1)/this.duration
        this.detaY = (this.scaleY - 1)/this.duration
    }
    run(_sprite) {
        _sprite.scaleX += this.detaX
        _sprite.scaleY += this.detaY
        this.currentFrame--
        if(this.currentFrame > 0 && this.running) {
            setTimeout(()=>{this.run(_sprite)}, Math.round(1000/60))
        }
    }
}
okay.ActionRotate = class extends okay.Action {
    constructor(_duration, _rotate) {
        super(_duration)
        this.rotate = _rotate
        this.deta = _rotate / this.duration
    }
    run(_sprite) {
        _sprite.rotation += this.deta
        this.currentFrame--
        if(this.currentFrame > 0 && this.running) {
            setTimeout(()=>{this.run(_sprite)}, Math.round(1000/60))
        }
    }
}
okay.ActionAlpha = class extends okay.Action {
    constructor(_duration, _alpha) {
        super(_duration)
        this.alpha = _alpha
        this.delta = (this.alpha - 1) / this.duration
    }
    run(_sprite) {
        _sprite.alpha += this.delta
        _sprite.alpha < 0?_sprite.alpha = 0:undefined
        this.currentFrame--
        if(this.currentFrame > 0 && this.running) {
            setTimeout(()=>{this.run(_sprite)}, Math.round(1000/60))
        }
    }
}
okay.Event = class {
    constructor(_event, _callback) {
        this.event = _event
        this.callback = _callback
    }
}
okay.Event.Type = {
    EVENT_MOUSE_DOWN:'event_mouse_down',
    EVENT_MOUSE_MOVE:'event_mouse_move',
    EVENT_MOUSE_UP:'event_mouse_up',
    EVENT_KEY_DOWN:'event_key_down',
    EVENT_KEY_PRESS:'event_key_press',
    EVENT_KEY_UP:'event_key_up'
}
okay.Listener = class {
    constructor(_obj, _event) {
        if(_obj instanceof okay.Node && _event instanceof okay.Event) {
            this.obj = _obj
            this.event = _event
        }else {
            throw 'Error Arguments'
        }
    }
}

okay.EventManager = class {
    constructor(canvas) {
        this.canvas = canvas
        this.listeners = new Array()
        this.canvas.ele.onmousedown = (e) => {this.downFunc(e)}
        this.canvas.ele.onmouseup = (e) => {this.upFunc(e)}
        this.canvas.ele.onmousemove = (e) => {this.moveFunc(e)}
        this.canvas.ele.onkeydown = (e) => {this.key_downFunc(e)}
        this.canvas.ele.onkeypress = (e) => {this.key_pressFunc(e)}
        this.canvas.ele.onkeyup = (e) => {this.key_upFunc(e)}
    }
    addEventListener(listener) {
        if(listener instanceof okay.Listener) {
            this.listeners.push(listener)
        }else {
            throw 'Error Arguments'
        }
    }
    removeEventListener(listener) {
        for(let i = 0;i < this.listeners.length;i++) {
            let l = this.listeners[i]
            if(l.event.event == listener.event.event) {
                this.listeners.splice(index, 1)
                break
            }

        }

    }
    mouseEvent(e, event) {
        //检测被选中的元素
        if(event == okay.Event.Type.EVENT_MOUSE_DOWN) {
            let has = false
            for(let item of this.canvas.childs) {
                let _p = new okay.Point(e.pageX, this.canvas.height - e.pageY)
                if(item.containPoint(_p)) {
                    if(this.canvas.selectNode != item && this.canvas.selectNode != null) {
                        this.canvas.selectNode.is_selected = false
                        let unret = true
                        if(this.canvas.selectNode instanceof okay.Layer) {
                            unret = this.canvas.selectNode.doChildUnSelected(_p)
                        }
                        if(unret && this.canvas.selectNode.onUnSelected) {
                            this.canvas.selectNode.onUnSelected()
                        }
                    }
                    this.canvas.selectNode = item
                    this.canvas.selectNode.is_selected = true
                    let ret = true
                    if(this.canvas.selectNode instanceof okay.Layer){
                        ret = this.canvas.selectNode.doChildSelected(_p)
                    }
                    if(ret && this.canvas.selectNode.onSelected) {
                        this.canvas.selectNode.onSelected()
                    }
                    has = true
                    break;
                }
            }
            if(!has) {
                if(this.canvas.selectNode != null) {
                    this.canvas.selectNode.is_selected = false
                    let unret2 = true
                    if(this.canvas.selectNode instanceof okay.Layer){
                        unret2 = this.canvas.selectNode.doChildUnSelected(null)
                    }
                    if(unret2 && this.canvas.selectNode.onUnSelected) {
                        this.canvas.selectNode.onUnSelected()
                    }
                }
                this.canvas.selectNode = null
            }
        }
        for(let listener of this.listeners) {
            if(listener.obj != null && listener.obj instanceof okay.Node) {
                if(listener.event.event == event
                    && listener.obj.containPoint(new okay.Point(e.pageX, this.canvas.height - e.pageY))) {
                    listener.event.callback(e, listener.obj)
                }
            }
        }
    }
    triggerEvent(event, _obj) {
        for(let listener of this.listeners) {
            if(listener.event.event == event && listener.obj == _obj) {
                listener.event.callback(event, listener.obj)
            }
        }
    }
    downFunc(e){
        this.mouseEvent(e,okay.Event.Type.EVENT_MOUSE_DOWN)
    }
    upFunc(e){
        this.mouseEvent(e,okay.Event.Type.EVENT_MOUSE_UP)
    }
    moveFunc(e){
        this.mouseEvent(e,okay.Event.Type.EVENT_MOUSE_MOVE)
    }
    keyEvent(e, event) {
        for(let listener of  this.listeners) {
            if(listener.obj != null && listener.obj instanceof okay.Node) {
                if (listener.event.event == event && listener.obj.is_selected) {
                    listener.event.callback(e, listener.obj)
                }
            }
        }
    }
    key_downFunc(e) {
        this.keyEvent(e, okay.Event.Type.EVENT_KEY_DOWN)
    }
    key_pressFunc(e) {
        this.keyEvent(e, okay.Event.Type.EVENT_KEY_PRESS)
    }
    key_upFunc(e) {
        this.keyEvent(e, okay.Event.Type.EVENT_KEY_UP)
    }
}

okay.Rect = class {
    constructor(_originX, _originY, _width, _height) {
        this.originX = _originX
        this.originY = _originY
        this.width = _width
        this.height = _height
    }
    containPoint(point, y = 0) {
        if(point instanceof okay.Point) {
            if(point.x > (this.originX + this.width) || point.x < this.originX){
                return false;
            }
            if(point.y < (this.originY - this.height) || point.y > this.originY){
                return false;
            }
            return true;
        }else {
            if(point > (this.originX + this.width) || point < this.originX) {
                return false
            }
            if(y > (this.originY + this.height) || y < this.originY) {
                return false
            }
            return true
        }
    }
    getArea () {
        return this.width * this.height
    }
    isCross(rect) {
        if(rect instanceof okay.Rect) {
            if(this.getArea() > rect.getArea()) {
                return this.containPoint(rect.originX, rect.originY)||
                    this.containPoint(rect.originX + rect.width,rect.originY)||
                    this.containPoint(rect.originX, rect.originY + rect.height)||
                    this.containPoint(rect.originX + rect.width, rect.originY + rect.height)
            }else {
                return rect.containPoint(this.originX, this.originY)||
                    rect.containPoint(this.originX + this.width, this.originY)||
                    rect.containPoint(this.originX, this.originY + this.height)||
                    rect.containPoint(this.originX + this.width, this.originY + this.height)
            }
        }else{
            throw 'Error Arguments'
        }
    }
}

okay.Node = class {
    constructor() {
        this.position = new okay.Point(0, 0)
        this.size = new okay.Size(0, 0)
        this.visible = true
        this.rotation = 0
        this.scaleX = 1
        this.scaleY = 1
        this.alpha = 1
        this.schedulers = new Array()
        this.canvas = null
        this.is_selected = false
    }
    setPosition(_x, _y = 0) {
        if (_x instanceof okay.Point) {
            this.position = _x
        }else {
            this.position = new okay.Point(_x, _y)
        }
    }
    getPosition() {
        return this.position
    }
    setSize(_width, _height = 0) {
        if(_width instanceof okay.Size) {
            this.size = _width
        }else {
            this.size.width = _width
            this.size.height = _height
        }
    }
    scheduleUpdate(dt) {
        this.updateScheduler = setInterval((dt) => {this.update(dt)}, dt)
    }
    unschedulerUpdate() {
        clearInterval(this.updateScheduler)
    }
    update(dt) {}
    schedule(_callback, dt) {
        let scheduler = setInterval(_callback(dt), dt)
        this.schedulers.push(
            new okay.Scheduler(scheduler, _callback)
        )
    }
    runAction(_action) {
        if(_action instanceof okay.Action) {
            _action.reset()
            _action.run(this)
        }else {
            throw 'Error Arguments'
        }
    }
    stopAction(_action) {
        if(_action instanceof okay.Action) {
            _action.stop()
        }else {
            throw 'Error Arguments'
        }
    }
    unscheduler(_callback) {
        for(let i in this.schedulers) {
            let scheduler =  this.schedulers[i]
            if(scheduler.callback == _callback) {
                this.schedulers.slice(i, 1)
                clearInterval(scheduler.scheduler)
                break
            }
        }
    }
    getContentBounding() {
        return new okay.Rect(this.position.x,
            this.position.y,
            this.size.width,
            this.size.height)
    }
    containPoint(_p) {
        let rect = this.getContentBounding()
        return rect.containPoint(_p)
    }
    addEventListener(_event, _callback) {
        if(this.canvas == undefined || this.canvas == null) {
            throw 'No Canvas Found'
        }
        let event = new okay.Event(_event, _callback)
        let listener = new okay.Listener(this, event)
        this.canvas.eventManager.addEventListener(listener)
    }
    removeEventListener(_event, _callback) {
        if(this.canvas == undefined || this.canvas == null) {
            throw 'No Canvas Found'
        }
        let event = new okay.Event(_event, _callback)
        let listener = new okay.Listener(this, event)
        this.canvas.eventManager.removeEventListener(listener)
    }
    trigger(_event) {
        if(this.canvas == undefined || this.canvas == null) {
            throw 'No Canvas Found'
        }
        this.canvas.eventManager.triggerEvent(_event, this)
    }
    draw(painter) {

    }
    paint() {
        if(this.visible) {
            let painter = this.canvas.painter
            painter.save()
            painter.globalAlpha = this.alpha
            painter.translate(0, this.scaleY * (this.canvas.height - 2 * this.position.y))
            painter.rotate(this.rotation * Math.PI / 180)
            painter.scale(this.scaleX, this.scaleY)
            this.draw(painter)
            painter.restore()
        }
    }
}

okay.Layer = class extends okay.Node {
    constructor() {
        super()
        this.childs = new Array()
        this.selectNode = null
    }
    doChildSelected(_p) {
        let ret = true
        for(let item of this.childs){
            if(item.containPoint(_p)) {
                if(this.selectNode != item && this.selectNode != null) {
                    this.selectNode.is_selected = false
                    if(this.selectNode instanceof okay.Layer) {
                        this.selectNode.doChildUnSelected(_p)
                    }
                    if(this.selectNode.onUnSelected) {
                        this.selectNode.onUnSelected()
                    }
                }
                this.selectNode = item
                this.selectNode.is_selected = true
                if(this.selectNode instanceof okay.Layer){
                    ret = this.selectNode.doChildSelected(_p)
                }
                if(ret && this.selectNode.onSelected) {
                    ret = this.selectNode.onSelected()
                }
            }
        }
        return ret
    }
    doChildUnSelected(_p) {
        let ret = true
        if(this.selectNode != null) {
            if(this.selectNode instanceof okay.Layer) {
                ret = this.selectNode.doChildUnSelected(_p)
            }
            if(ret && this.onUnSelected) {
                ret = this.onUnSelected()
            }
            this.selectNode.is_selected = false
        }
        return ret
    }
    addChild(child) {
        if(child instanceof okay.Node) {
            if(this.childs.indexOf(child) == -1) {
                this.childs.push(child)
                child.canvas = this.canvas
            }else {
                this.childs.splice(this.childs.indexOf(child), 1)
                this.childs.push(child)
                child.canvas = this.canvas
            }
        }
    }
    removeChild(child) {
        if(this.childs.indexOf(child) != -1) {
            this.childs.splice(this.childs.indexOf(child), 1)
        }
    }
    paint() {
        if(this.visible) {
            for(let child of this.childs) {
                child.paint()
            }
        }
    }
}
okay.DebugLayer = class extends okay.Layer {
    constructor(canvas) {
        super()
        this.canvas = canvas
        this.hline = new okay.Line(new okay.Point(0,0),new okay.Point(this.canvas.width,0))
        this.vline = new okay.Line(new okay.Point(0,0),new okay.Point(0, this.canvas.height))
        this.hline.lineWidth = 1
        this.vline.lineWidth = 1
        this.addChild(this.hline)
        this.addChild(this.vline)
        this.rect = null
        this.tip = new okay.Text('')
        this.startPoint = null
        this.endPoint = null
        this.tip.color = new okay.Color(0,0,0,255)
        this.tip.font = "5px"
        this.addChild(this.tip)
        this.addEventListener(okay.Event.Type.EVENT_MOUSE_DOWN,(e, obj) => {
            if(obj.rect != null) {
                obj.removeChild(obj.rect)
                obj.rect = null
                obj.tip.text = ''
            }
            obj.startPoint = new okay.Point(e.pageX - this.canvas.ele.offsetLeft, e.pageY - this.canvas.ele.offsetTop)
        })
        this.addEventListener(okay.Event.Type.EVENT_MOUSE_MOVE,(e,obj) => {
            if(this.startPoint != null) {
                if(obj.rect != null) {
                    obj.removeChild(obj.rect)
                }
                obj.endPoint = new okay.Point(e.pageX - this.canvas.ele.offsetLeft, e.pageY - this.canvas.ele.offsetTop)
                obj.rect = new okay.Rectangle()
                obj.rect.setColor(new okay.Color(55,55,255))
                obj.rect.alpha = 0.5
                obj.rect.setPosition(obj.startPoint.x, this.canvas.height - obj.startPoint.y)
                obj.rect.setSize(obj.endPoint.x - obj.startPoint.x, obj.endPoint.y - obj.startPoint.y)
                obj.addChild(obj.rect)
                obj.tip.text = "(" +  obj.startPoint.x + "," +  (this.canvas.height - obj.startPoint.y) + ","
                    + (obj.endPoint.x - obj.startPoint.x) + ","+  (obj.endPoint.y - obj.startPoint.y) + ")"
                obj.tip.setPosition(obj.endPoint.x, this.canvas.height - obj.endPoint.y)
            }
            obj.hline.to.y = obj.hline.from.y = this.canvas.height - (e.pageY - this.canvas.ele.offsetTop) + 0.5
            obj.vline.to.x = obj.vline.from.x = e.pageX - this.canvas.ele.offsetLeft + 0.5
        })
        this.addEventListener(okay.Event.Type.EVENT_MOUSE_UP,(e, obj) => {
            if(obj.rect != null) {
                obj.removeChild(obj.rect)
            }
            obj.endPoint = new okay.Point(e.pageX - this.canvas.ele.offsetLeft, e.pageY - this.canvas.ele.offsetTop)
            obj.rect = new okay.Rectangle()
            obj.rect.setColor(new okay.Color(55,55,255))
            obj.rect.alpha = 0.5
            obj.rect.setPosition(obj.startPoint.x, this.canvas.height - obj.startPoint.y)
            obj.rect.setSize(obj.endPoint.x - obj.startPoint.x, obj.endPoint.y - obj.startPoint.y)
            obj.addChild(obj.rect)
            obj.tip.text = "(" +  obj.startPoint.x + "," +  (this.canvas.height - obj.startPoint.y) + ","
                + (obj.endPoint.x - obj.startPoint.x) + ","+  (obj.endPoint.y - obj.startPoint.y) + ")"
            obj.tip.setPosition(obj.endPoint.x, this.canvas.height - obj.endPoint.y)
            this.startPoint = null
            this.endPoint = null
        })
        this.addEventListener(okay.Event.Type.EVENT_KEY_PRESS,(e, obj) => {
            console.log(e.code)
        })
    }
    containPoint(_p) {
        return true
    }

}
okay.Color = class {
    constructor(_r, _g, _b, _a) {
        this.r = _r
        this.g = _g
        this.b = _b
        this.a = _a
    }
    getColor() {
        let r16 = (this.r>16)?(this.r%256).toString(16):("0"+(this.r%256).toString(16))
        let g16 = (this.g>16)?(this.g%256).toString(16):("0"+(this.g%256).toString(16))
        let b16 = (this.b>16)?(this.b%256).toString(16):("0"+(this.b%256).toString(16))
        return "#"+r16+g16+b16
    }
    add(_c){
        this.r += _c.r
        this.g += _c.g
        this.b += _c.b
        this.a += _c.a

    }
    sub(_c){
        this.r -= _c.r
        this.g -= _c.g
        this.b -= _c.b
        this.a -= _c.a
    }
    digMul(_c){
            this.r = Math.round(this.r + this.r * _c.r),
            this.g = Math.round(this.g + this.g * _c.g),
            this.b = Math.round(this.b + this.b * _c.b),
            this.a = Math.round(this.a + this.a * _c.a)
    }
    ldMul(lamda){
        if(lamda < 1 && lamda >0){
            this.r = Math.floor(this.r * lamda)
            this.g = Math.floor(this.g * lamda)
            this.b = Math.floor(this.b * lamda)
            this.a = Math.floor(this.a * lamda)
        }else{
            throw 'Error Arguments'
        }
    }
    changeAlpha(alpha){
        if(this.a+alpha <=255&&this.a+alpha >=0)
            this.a += alpha;
    }
    fadeIn(alpha){
        if(this.a <255)
            this.a += alpha;
    }
    fadeOut(alpha){
        if(this.a > 0)
            this.a -= alpha;
    }
}
okay.Rectangle = class extends okay.Node {
    constructor() {
        super()
        this.color = new okay.Color(0, 0,0,255)
    }
    setColor(_c) {
        this.color = _c
    }
    draw(painter) {
        painter.fillStyle = this.color.getColor()
        painter.fillRect(this.position.x, this.position.y, this.size.width, this.size.height)
    }
}
okay.HollowRectangle = class extends okay.Rectangle {
    constructor() {
        super()
        this.lineWidth = 5
    }
    setLineWidth(_w) {
        this.lineWidth = _w
    }
    draw(painter) {
        painter.storkeStyle = this.color.getColor()
        painter.lineWidth = this.lineWidth
        painter.strokeRect(this.position.x, this.position.y, this.size.width, this.size.height)
    }
}
okay.Line = class extends okay.Node {
    constructor( from, to) {
        super()
        this.color = new okay.Color(0, 0, 0, 255)
        this.from = from
        this.to = to
        this.lineWidth = 5
    }
    setColor(_c) {
        this.color = _c
    }
    setFrom(from, y = 0) {
        if(from instanceof  okay.Point) {
            this.from = from
        }else {
            this.from = new okay.Point(from, y)
        }
    }
    setTo(to, y = 0) {
        if(to instanceof okay.Point) {
            this.to = to
        }else {
            this.to = new okay.Point(to, y)
        }
    }
    setLineWidth(_w) {
        this.lineWidth = _w
    }
    draw(painter) {
        painter.fillStyle = this.color.getColor()
        painter.lineWidth = this.lineWidth
        painter.moveTo(this.from.x,  - this.from.y)
        painter.lineTo(this.to.x,  - this.to.y)
        painter.stroke()
    }
}

okay.Sector = class extends okay.Node {
    constructor( radius, start = 0, stop = 2 * Math.PI) {
        super()
        this.color = new okay.Color(0, 0, 0, 255)
        this.start = start
        this.stop = stop
        this.radius = radius
    }
    setStart(_start) {
        this.start = _start
    }
    setStop(_stop) {
        this.stop = _stop
    }
    setRadius(radius) {
        this.radius = radius
    }
    setColor(_c) {
        this.color = _c
    }
    containPoint(_p) {
        let dist = (_p.x - this.position.x)*(_p.x - this.position.x) + (_p.y - this.position.y) * (_p.y - this.position.y)
        if(dist > this.radius * this.radius) {
            return false
        }
        let tan = -(_p.y - this.position.y)/(_p.x - this.position.x)
        let atan = Math.atan(tan)
        if(_p.x < this.position.x && _p.y < this.position.y) {
            atan = Math.PI + atan
        }else if(_p.x < this.position.x && _p.y > this.position.y) {
            atan = Math.PI * 3/2 + atan
        }else if(_p.x > this.position.x && _p.y > this.position.y) {
            atan = Math.PI * 2 + atan
        }
        if(this.stop < this.start) {
            return  atan >= this.start || atan <= this.stop
        }else {
            return atan >= this.start && atan <= this.stop
        }
    }
    draw(painter) {
        painter.fillStyle = this.color.getColor()
        painter.beginPath()
        painter.arc(this.position.x / this.scaleX,this.position.y / this.scaleY, this.radius,this.start, this.stop)
        painter.lineTo(this.position.x / this.scaleX, this.position.y / this.scaleY)
        painter.closePath()
        painter.fill()
    }
}
okay.HollowSector = class extends okay.Sector {
    constructor( radius, start = 0, stop = 2 * Math.PI) {
        super(radius, start, stop)
        this.lineWidth = 5
    }
    setLineWidth(_w) {
        this.lineWidth = _w
    }
    draw(painter) {
        painter.beginPath()
        painter.strokeStyle = this.color.getColor()
        painter.lineWidth = this.lineWidth
        painter.arc(this.position.x / this.scaleX, this.position.y / this.scaleY, this.radius,this.start, this.stop)
        painter.lineTo(this.position.x / this.scaleX, this.position.y / this.scaleY)
        painter.closePath()
        painter.stroke()
    }
}

okay.Circle = class extends okay.Sector {
    constructor(radius) {
        super(radius)
    }
    containPoint(_p) {
        let dist = (_p.x - this.position.x)*(_p.x - this.position.x)+(_p.y - this.position.y) * (_p.y - this.position.y)
        return dist <= this.radius * this.radius
    }

}
okay.HollowCircle = class extends okay.HollowSector{
    constructor(radius) {
        super(radius)
    }
    containPoint(_p) {
        let dist = (_p.x - this.position.x)*(_p.x - this.position.x)+(_p.y - this.position.y) * (_p.y - this.position.y)
        return dist <= this.radius * this.radius
    }
    draw(painter) {
        painter.beginPath()
        painter.strokeStyle = this.color.getColor()
        painter.lineWidth = this.lineWidth
        painter.arc(this.position.x / this.scaleX, this.position.y / this.scaleY, this.radius,this.start, this.stop)

        painter.stroke()
    }
}
okay.Text = class extends okay.Node {
    constructor(text = '', font = '30px Arial') {
        super()
        this.text = text
        this.font = font
        this.color = new okay.Color(255, 255, 255, 255)
    }
    setColor(_c) {
        this.color = _c
    }
    draw(painter) {
        painter.font = this.font
        painter.fillStyle = this.color.getColor()
        painter.fillText(this.text, this.position.x / this.scaleX, this.position.y / this.scaleY)
    }
}
okay.ActionInput = class extends okay.Action {
    update(node, currentFrame) {
        if(this.currentFrame < Math.round(this.duration/2)) {
            if(node.cursor == node.value.length){
                node.text = node.value + "|"
            }else if(node.cursor < node.value.length){
                node.text = node.value.substr(0,node.cursor) + "|" + node.value.substr(node.cursor,node.value.length)
            }

        }else {
            node.text = node.value
        }

        if(this.currentFrame == 1) {
            this.currentFrame = this.duration
        }
    }

}
okay.EditText = class extends okay.Node {
    constructor(canvas,text = '',font = '30px Arial') {
        super()
        this.canvas = canvas
        this.text = text
        this.font = font
        this.color = new okay.Color(255,255,255,255)
        this.dom = document.createElement("input")
        this.dom.style.position = "absolute"
        this.dom.style.top = "-999px"
        this.dom.style.left = "-999px"
        this.value = this.text
        this.dom.value = this.value
        this.domLock = false
        this.dom.addEventListener('compositionstart',()=>{this.domLock = true})
        this.dom.addEventListener('compositionend',(e)=>{
            this.domLock = false
            this.cursor += e.target.value.length - this.value.length
            this.value = e.target.value
        })
        this.dom.addEventListener('input', (e) => {
            if(!this.domLock) {
                this.cursor += e.target.value.length - this.value.length
                this.value = e.target.value
            }
        })
        this.dom.addEventListener('keydown',(e) => {
            if(e.code == "ArrowLeft") {
                if (this.cursor > 0) {
                    this.cursor--
                }
            }
            if(e.code == "ArrowRight"){
                if (this.cursor < this.value.length) {
                    this.cursor++
                }
            }
        })
        this.cursor = this.value.length//光标的位置
        document.body.appendChild(this.dom)
        this.addEventListener(okay.Event.Type.EVENT_KEY_DOWN,(e,obj) => {
            this.dom.focus()
            if(e.code == "ArrowLeft") {
                if (this.cursor > 0) {
                    this.cursor--
                }
            }
            if(e.code == "ArrowRight"){
                if (this.cursor < this.value.length) {
                    this.cursor++
                }
            }
        })
        this.action = new okay.ActionInput(1)
    }
    setPosition(_x,_y) {
        super.setPosition(_x, _y)
    }
    getContentBounding(_p) {
        let font_size = parseFloat(this.font.match(/([0-9]+.?[0-9]*)px/)[1])
        return new okay.Rect(this.position.x, this.position.y + font_size, font_size * this.text.length,font_size)
    }
    onSelected() {
        this.action.restart(this)
    }
    onUnSelected() {
        this.action.stop()
        setTimeout(()=>{
            this.text = this.value
        },1000/60)//确保在动画下一帧执行

    }
    draw(painter) {
        painter.font = this.font
        painter.fillStyle = this.color.getColor()
        painter.fillText(this.text, this.position.x / this.scaleX, this.position.y / this.scaleY)
    }

}
okay.Triangle = class extends okay.Node {
    constructor(p1, p2, p3) {
        super()
        this.p1 = p1
        this.p2 = p2
        this.p3 = p3
        this.color = new okay.Color(0, 0, 0, 255)
    }
    setColor(_c) {
        this.color = _c
    }
    draw(painter) {
        painter.translate(0, -this.canvas.height/this.scaleY)
        painter.beginPath()
        painter.fillStyle = this.color.getColor()

        painter.moveTo(this.p1.x * this.scaleX, (this.canvas.height - this.p1.y)*this.scaleY)
        painter.lineTo(this.p2.x * this.scaleX, (this.canvas.height - this.p2.y)*this.scaleY)
        painter.lineTo(this.p3.x * this.scaleX, (this.canvas.height - this.p3.y)*this.scaleY)
        painter.fill()
    }
    containPoint(_p){
        let p1 = [_p.x - this.p1.x, -_p.y + this.p1.y],
            p2 = [_p.x - this.p2.x, -_p.y + this.p2.y],
            p3 = [_p.x - this.p3.x, -_p.y + this.p3.y]
        let cos1 = (p1[0] * p2[0] + p1[1] * p2[1])/Math.sqrt((p1[0] * p1[0] + p1[1] * p1[1]) * (p2[0]*p2[0] + p2[1]*p2[1]))
        let cos2 = (p1[0] * p3[0] + p1[1] * p3[1])/Math.sqrt((p1[0] * p1[0] + p1[1] * p1[1]) * (p3[0]*p3[0] + p3[1]*p3[1]))
        let cos3 = (p3[0] * p2[0] + p3[1] * p2[1])/Math.sqrt((p3[0] * p3[0] + p3[1] * p3[1]) * (p2[0]*p2[0] + p2[1]*p2[1]))
        return Math.acos(cos1) + Math.acos(cos2) + Math.acos(cos3) == Math.PI * 2
    }
}
okay.HollowTriangle = class extends okay.Triangle {
    constructor(p1, p2, p3) {
        super(p1, p2, p3)
        this.lineWidth = 5
    }
    setLineWidth(_w) {
        this.lineWidth = _w
    }
    draw(painter) {
        painter.translate(0, -this.canvas.height/this.scaleY)
        painter.beginPath()
        painter.moveTo(this.p1.x * this.scaleX, (this.canvas.height - this.p1.y) * this.scaleY)
        painter.lineTo(this.p2.x * this.scaleX, (this.canvas.height - this.p2.y) * this.scaleY)
        painter.lineTo(this.p3.x * this.scaleX, (this.canvas.height - this.p3.y) * this.scaleY)
        painter.closePath()
        painter.strokeStyle = this.color.getColor()
        painter.lineWidth = this.lineWidth
        painter.stroke()
    }
}
okay.Ellipse = class extends okay.Node {
    constructor(a, b) {
        super()
        this.a = a
        this.b = b
        this.color = new okay.Color(0, 0, 0, 255)
    }
    setColor(_c) {
        this.color = _c
    }
    draw(painter) {
        painter.fillStyle = this.color.getColor()
        let mx = this.a > this.b?this.a:this.b
        let x = this.a/mx
        let y = this.b/mx
        painter.scale(x , y)
        painter.arc(this.position.x/x/this.scaleX, this.position.y/y/this.scaleY, mx, 0, 2 * Math.PI)
        painter.lineTo(this.position.x/x/this.scaleX, this.position.y/y/this.scaleY)
        painter.fill()
    }
    containPoint(_p) {
        let tmp = (_p.x - this.position.x)*(_p.x - this.position.x)/this.a/this.a
                    + (_p.y - this.position.y) * (_p.y - this.position.y)/this.b/this.b
        return tmp <= 1
    }
}
okay.HollowEllipse = class extends okay.Ellipse {
    constructor(a, b) {
        super(a, b)
        this.lineWidth = 5
    }
    setLineWidth(_w) {
        this.lineWidth = _w
    }
    draw(painter) {
        painter.strokeStyle = this.color.getColor()
        painter.lineWidth = this.lineWidth
        let mx = this.a > this.b?this.a:this.b
        let x = this.a/mx
        let y = this.b/mx
        painter.scale(x , y)
        painter.arc(this.position.x/x/this.scaleX, this.position.y/y, mx/this.scaleY, 0, 2 * Math.PI)
        painter.stroke()
    }
}


okay.Image = class extends okay.Node {
    constructor(fileName, _rect) {
        super()
        this.img = new Image()
        if (arguments.length ==  1) {
            this.img.src = fileName
            this.rect = new okay.Rect(0, 0, this.img.width, this.img.height)
        }else if(arguments.length == 2) {
            this.img.src = fileName
            this.rect = _rect
        }else {
            throw 'Error Arguments'
        }
    }
    resetTexture(_rect){
        if((_rect.originX+_rect.width) < this.img.width&&
            (_rect.originY+_rect.height) < this.img.height&&
            (_rect.originX+_rect.width) > 0&&
            (_rect.originY+_rect.height) > 0)
            this.rect = _rect
        else{
            throw 'Out of Bounding'
        }
    }
    draw(painter) {
        painter.translate(this.position.x, this.position.y)
        painter.drawImage(this.img,this.rect.originX,this.rect.originY,this.rect.width,this.rect.height,-this.rect.width/2,-this.rect.height/2,this.rect.width,this.rect.height)
    }
}
//export {okay}